package com.ctshk.rpc.air.service.impl.app;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.*;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.utils.Assert;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.common.utils.ValidatorUtil;
import com.ctshk.rpc.air.dto.*;
import com.ctshk.rpc.air.dto.app.AirProductListDTO;
import com.ctshk.rpc.air.dto.app.AirRecommendListDTO;
import com.ctshk.rpc.air.dto.app.*;
import com.ctshk.rpc.air.dto.pc.AirFlightListDTO;
import com.ctshk.rpc.air.dto.pc.HotCityDTO;
import com.ctshk.rpc.air.dto.pc.PcAirProductListDTO;
import com.ctshk.rpc.air.entity.*;
import com.ctshk.rpc.air.entity.es.AirProductEs;
import com.ctshk.rpc.air.mapper.*;
import com.ctshk.rpc.air.req.AirPortListReq;
import com.ctshk.rpc.air.req.AirProductReservationSettingsDataReq;
import com.ctshk.rpc.air.req.ProductFullPriceReq;
import com.ctshk.rpc.air.req.app.AirTicketsListReq;
import com.ctshk.rpc.air.req.app.MainDataRowFieldDataReq;
import com.ctshk.rpc.air.service.IAirProductChannelOnlineSelfPlatformService;
import com.ctshk.rpc.air.service.IAirProductCostTouristService;
import com.ctshk.rpc.air.service.IAirProductSaleRecordService;
import com.ctshk.rpc.air.service.IAirProductService;
import com.ctshk.rpc.air.service.app.IAirProductAppService;
import com.ctshk.rpc.air.service.impl.es.AirProductEsService;
import com.ctshk.rpc.cms.req.BannerPositionByTypeReq;
import com.ctshk.rpc.cms.service.INoticeService;
import com.ctshk.rpc.system.dto.MainDataRowDTO;
import com.ctshk.rpc.system.service.IMainDataTableService;
import com.ctshk.rpc.system.service.ISysAreaService;
import com.github.houbb.heaven.util.lang.StringUtil;
import com.github.houbb.heaven.util.util.CollectionUtil;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.Period;
import java.util.*;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @BelongsProject: ctshk-cloud
 * @BelongsPackage: com.ctshk.rpc.air.service.impl.app
 * @Author: hef
 * @CreateTime: 2021-04-19 15:09
 * @Description: 描述
 */
@DubboService
public class AirProductAppServiceImpl extends ServiceImpl<AirProductMapper, AirProduct> implements IAirProductAppService {

    @Resource
    private IAirProductService iAirProductService;
    @Resource
    private AirProductMapper airProductMapper;
    @Resource
    private AirProductEsService airProductEsService;
    @Resource
    private AirFlightMapper airFlightMapper;
    @Resource
    private AirProductReservationSettingsMapper airProductReservationSettingsMapper;
    @Resource
    private AirProductCostTouristMapper airProductCostTouristMapper;
    @Resource
    private IAirProductCostTouristService airProductCostTouristService;
    @Resource
    private IAirProductChannelOnlineSelfPlatformService airProductChannelOnlineSelfPlatformService;
    @DubboReference
    private IMainDataTableService mainDataTableService;
    @Resource
    private IAirProductSaleRecordService iAirProductSaleRecordService;

    @DubboReference
    private INoticeService iNoticeService;

    @DubboReference
    private IMainDataTableService iMainDataTableService;

    @Resource
    private MainDataAirAirportMapper mainDataAirAirportMapper;
    /**
     * 表字段数据
     */
    @Autowired
    private MainDataFieldDataMapper mainDataFieldDataMapper;
    @Autowired
    private SysAreaMapper sysAreaMapper;

    @DubboReference
    private ISysAreaService areaService;

    /**
     * app-air-product/getTicketList查询机票列表
     * @param req
     * @return
     */
    @Override
    public Result<PageResponse<AirProductListDTO>> getTicketList(AirTicketsListReq req) {
        Page<AirProductEs> page = airProductEsService.searchListPage(req.setChannelId(ChannelMainData.APP_H5.getId()));
        List<AirProductEs> list = airProductEsService.calculateTheMinimumPrice(ChannelMainData.APP_H5.getId(),req.getCurrentTimes(), page.getContent());
        return Result.success(new PageResponse<>(
                EntityUtil.copyList(list, AirProductListDTO.class),
                req.getPageNo() == 1, req.getPageNo().equals(page.getTotalPages()), page.getTotalElements(), req.getPageNo(), page.getSize()
        ));
    }

    /**
     * 推荐机票查询
     * @return
     */
    @Override
    public List<AirRecommendListDTO> getRecommendedTicket() {
        List<AirProductEs> recommendedTicket = airProductEsService.getRecommendedTicket(1L);
        List<AirRecommendListDTO> airRecommendList = EntityUtil.copyList(recommendedTicket, AirRecommendListDTO.class);
        return airRecommendList;
    }

    @Override
    public AirProductDetailDTO getProductDetail(Long id, LocalDate date, long channelId) {
        //获取机票
        AirProduct airProduct = airProductMapper.selectById(id);
        Assert.nonNull(airProduct, SystemError.AIR_PRODUCT_12004);
        //获取航班信息
        AirFlight airFlight = airFlightMapper.selectById(airProduct.getRouteId());
        Assert.nonNull(airFlight, SystemError.AIR_PRODUCT_12023);
        //组装数据
        AirProductDetailDTO dto = EntityUtil.copy(airProduct, AirProductDetailDTO.class);
        BeanUtils.copyProperties(airFlight, dto);
        dto.setId(id);
        //获取预订信息
        AirProductReservationSettings reservationSettings = airProductReservationSettingsMapper.selectOne(
                Wrappers.<AirProductReservationSettings>lambdaQuery()
                        .eq(AirProductReservationSettings::getAirProductId, airProduct.getId())
        );
        AirProductReservationSettingsDataReq settingsDataReq =
                EntityUtil.copy(reservationSettings, AirProductReservationSettingsDataReq.class);
        dto.setAirProductReservationSettingsDataReq(settingsDataReq);
        //获取成本信息
        List<AirProductCostTouristDTO> list = airProductCostTouristService.getCurrentlyValidData(id, date);
        Assert.notEmpty(list, SystemError.AIR_PRODUCT_12025);
        //获取线上加幅
        AirProductChannelOnlineSelfPlatformDTO currentlyValidIncrease =
                airProductChannelOnlineSelfPlatformService.getCurrentlyValidData(id, date, channelId);
        Assert.nonNull(currentlyValidIncrease, SystemError.AIR_PRODUCT_12026);
        List<AirProductTouristPriceDTO> touristPrice = list.stream().map(item -> {
            AirProductTouristPriceDTO copy = EntityUtil.copy(item, AirProductTouristPriceDTO.class);
            //售卖价格
            BigDecimal salePrice;
            //加数值
            if (NumberConstant.ONE.getValue().equals(currentlyValidIncrease.getAdjustType())) {
                salePrice = item.getCostPrice().add(currentlyValidIncrease.getAmount());
            }
            //加百分比
            else {
                salePrice = item.getCostPrice().add(item.getCostPrice().multiply(
                        BigDecimal.valueOf(currentlyValidIncrease.getPercent()).divide(BigDecimal.valueOf(100))
                ));
            }
            copy.setSalePrice(salePrice);
            return copy;
        }).collect(Collectors.toList());
        dto.setAirProductTouristPrice(touristPrice);
        return dto;
    }

    /**
     * 获取多程机票详情
     * @param id
     * @param date
     * @param channelId
     * @return
     */
    @Override
    public List<AirProductDetailDTO> getMultipassProductDetail(String id, LocalDate date, long channelId) {
        List<AirProductDetailDTO>  airProductDetailList= new ArrayList<>();

        String substring = id.substring(0, id.length() - 1);
        String[] result = substring.split(",");
        for (String idAttr : result) {
            //获取机票
            AirProduct airProduct = airProductMapper.selectById(id);
            Assert.nonNull(airProduct, SystemError.AIR_PRODUCT_12004);
            //获取航班信息
            AirFlight airFlight = airFlightMapper.selectById(airProduct.getRouteId());
            Assert.nonNull(airFlight, SystemError.AIR_PRODUCT_12023);
            //组装数据
            AirProductDetailDTO dto = EntityUtil.copy(airProduct, AirProductDetailDTO.class);
            BeanUtils.copyProperties(airFlight, dto);
            dto.setId(Long.valueOf(idAttr));
            //获取预订信息
            AirProductReservationSettings reservationSettings = airProductReservationSettingsMapper.selectOne(
                    Wrappers.<AirProductReservationSettings>lambdaQuery()
                            .eq(AirProductReservationSettings::getAirProductId, airProduct.getId())
            );
            AirProductReservationSettingsDataReq settingsDataReq =
                    EntityUtil.copy(reservationSettings, AirProductReservationSettingsDataReq.class);
            dto.setAirProductReservationSettingsDataReq(settingsDataReq);
            //获取成本信息
            List<AirProductCostTouristDTO> list = airProductCostTouristService.getCurrentlyValidData(Long.valueOf(idAttr), date);
            Assert.notEmpty(list, SystemError.AIR_PRODUCT_12025);
            //获取线上加幅
            AirProductChannelOnlineSelfPlatformDTO currentlyValidIncrease =
                    airProductChannelOnlineSelfPlatformService.getCurrentlyValidData(Long.valueOf(idAttr), date, channelId);
            Assert.nonNull(currentlyValidIncrease, SystemError.AIR_PRODUCT_12026);
            List<AirProductTouristPriceDTO> touristPrice = list.stream().map(item -> {
                AirProductTouristPriceDTO copy = EntityUtil.copy(item, AirProductTouristPriceDTO.class);
                //售卖价格
                BigDecimal salePrice;
                //加数值
                if (NumberConstant.ONE.getValue().equals(currentlyValidIncrease.getAdjustType())) {
                    salePrice = item.getCostPrice().add(currentlyValidIncrease.getAmount());
                }
                //加百分比
                else {
                    salePrice = item.getCostPrice().add(item.getCostPrice().multiply(
                            BigDecimal.valueOf(currentlyValidIncrease.getPercent()).divide(BigDecimal.valueOf(100))
                    ));
                }
                copy.setSalePrice(salePrice);
                return copy;
            }).collect(Collectors.toList());
            dto.setAirProductTouristPrice(touristPrice);
            airProductDetailList.add(dto);
        }
        return airProductDetailList;
    }

    /**
     * app-air-product/getHomePageData 获取机票首页数据
     * @return
     */
    @Override
    public HomePageDataDto getHomePageData() {
        HomePageDataDto homePage = new HomePageDataDto();
        //推荐机票
        List<AirRecommendListDTO> recommendedTicket = getRecommendedTicket();
        homePage.setRecommendProduct(recommendedTicket);
        //航班主数据 main/data/table/query-table
        List<MainDataRowDTO> mainDataRowDTOS = mainDataTableService.queryData(1367377976054403073L);
        List<AirTicketsGradeDTO> ticketsGradeList = mainDataRowDTOS.stream()
                .map(item -> item.getList().get(0)).map(item -> {
                    return AirTicketsGradeDTO.builder().id(item.getId()).name(item.getFieldValue()).build();
                }).collect(Collectors.toList());
        homePage.setTicketsGrade(ticketsGradeList);

        //获取通告信息
        BannerPositionByTypeReq req = new BannerPositionByTypeReq();
        req.setCode("TEST_NOTICE");
        //List<com.ctshk.rpc.cms.dto.NoticeDTO> noticeDTO = iNoticeService.queryListByCode(req);
        List<NoticeDTO> noticeList = EntityUtil.copyList(iNoticeService.queryListByCode(req), NoticeDTO.class);
        homePage.setNotice(noticeList);

        return homePage;
    }


    /**
     * 查询机票列表
     * @param req
     * @return
     */
    @Override
    public List<AirFlightListDTO> getPcTicketList(AirTicketsListReq req) {
        List<AirProductEs> list = airProductEsService.searchListAttr(req.setChannelId(ChannelMainData.CHINA_TRAVEL.getId()));
        Map<Long, List<AirProductEs>> map = list.stream().collect(Collectors.groupingBy(AirProductEs::getFlightId));
        List<AirFlightListDTO> retList = Lists.newArrayList();
        map.forEach((k, v) -> {
            AirProductEs airProductEs = v.get(0);
            AirFlightListDTO airFlightListDTO = EntityUtil.copy(airProductEs, AirFlightListDTO.class);
            List<PcAirProductListDTO> productList = Lists.newArrayList();
            v.stream().forEach(item -> {
                PcAirProductListDTO copy = EntityUtil.copy(item, PcAirProductListDTO.class);
                if (item.getAirProductPriceSettingsDTO() != null) {
                    copy.setBookingInformation(item.getAirProductPriceSettingsDTO().getBookingInformation());
                    copy.setBaggageStates(item.getAirProductPriceSettingsDTO().getBaggageStates());
                }
                productList.add(copy);
            });
            airFlightListDTO.setProductList(productList);
            retList.add(airFlightListDTO);
        });
        return retList;
    }

    @Override
    public void saveEs() {
        airProductEsService.save();
    }

    @Override
    public List<CalendarLowestPriceDTO> getMonthFloorPrice(AirTicketsListReq req) {
        //获取日历
        //规则: 前后15天 如果前不足十五天 往后补
        List<LocalDate> dateList = getCalendar(req.getDepDate(), 15);
        List<CalendarLowestPriceDTO> list = dateList.parallelStream()
                .map(item -> {
                    BigDecimal min = BigDecimal.ZERO;
                    try {
                        List<AirProductEs> airProductEs = airProductEsService.searchList(req.setDepDate(item));
                        min = airProductEs.stream()
                                .map(AirProductEs::getLowPrice)
                                .min(BigDecimal::compareTo).get();
                    } catch (Exception e) {
                        log.error(e.getMessage());
                    }
                    return new CalendarLowestPriceDTO(item, min);
                })
                .collect(Collectors.toList());
        return list.stream().sorted(Comparator.comparing(CalendarLowestPriceDTO::getDate)).collect(Collectors.toList());
    }

    /**
     * 获取主数据提供C端
     * @param req
     * @return
     */
    public List<MainDataRowFieldDataDTO> queryFieldLikeName(MainDataRowFieldDataReq req) {
        com.ctshk.rpc.system.req.MainDataRowFieldDataReq attr = new com.ctshk.rpc.system.req.MainDataRowFieldDataReq();
        attr.setFid(req.getFid());
        attr.setName(req.getName());
        attr.setTid(req.getTid());
        List<com.ctshk.rpc.system.dto.MainDataRowFieldDataDTO>  mainDataRowFieldDataList = iMainDataTableService.queryDataFieldLikeName(attr);
        List<MainDataRowFieldDataDTO> mainDataRowFieldDataDto = EntityUtil.copyList(mainDataRowFieldDataList, MainDataRowFieldDataDTO.class);
        return mainDataRowFieldDataDto;
    }

    /**
     * 搜索获取国家、市区、机场信息
     * @param req
     * @return
     */
    @Override
    public List<MainDataAirAirportDTO> getAirportList(AirPortListReq req) {
        List<MainDataAirAirport> mainDataAirAirportList = mainDataAirAirportMapper.getAirportList(req.getName());
        List<MainDataAirAirport> mainDataAirAirportLists = Lists.newArrayList();
        if (CollectionUtil.isNotEmpty(mainDataAirAirportList)){
            for (MainDataAirAirport mainDataAirAirportAttr : mainDataAirAirportList){
                if (StringUtils.isNotBlank(mainDataAirAirportAttr.getAirportName())){
                    mainDataAirAirportLists.add(mainDataAirAirportAttr);
                }
            }
        }

        List<MainDataAirAirportDTO> mainDataAirAirportDto = EntityUtil.copyList(mainDataAirAirportLists, MainDataAirAirportDTO.class);
        return mainDataAirAirportDto;
    }


    /**
     * 获取最近30天的时间
     * 前15 后15
     *
     * @param localDate
     * @param interval  前后时间天数
     * @return
     */
    private List<LocalDate> getCalendar(LocalDate localDate, int interval) {
        LocalDate currentDate = LocalDate.now();
        Assert.isTrue(currentDate.compareTo(localDate) <= 0, SystemError.AIR_PRODUCT_12029);
        Period period = LocalDateTimeUtil.betweenPeriod(currentDate, localDate);
        int days = period.getDays();
        int gap = 0;
        if (days < interval) {
            gap = interval - days;
        }
        //获取前面时间
        List<LocalDate> frontDate = Stream.iterate(localDate.minusDays(interval - gap), date -> date.plusDays(1))
                .limit(interval - gap).collect(Collectors.toList());
        //获取后面的时间
        List<LocalDate> behindDate = Stream.iterate(localDate, date -> date.plusDays(1))
                .limit(interval + gap).collect(Collectors.toList());
        frontDate.addAll(behindDate);
        return frontDate;
    }


    @Override
    public ProductFullPriceAndStockDTO getProductFullPrice(ProductFullPriceReq req) {
        ValidatorUtil.validate(req);
        //获取机票
        AirProduct airProduct = airProductMapper.selectById(req.getProductId());
        Assert.nonNull(airProduct, SystemError.AIR_PRODUCT_12004);
        //获取预订信息
        AirProductReservationSettings reservationSettings = airProductReservationSettingsMapper.selectOne(
                Wrappers.<AirProductReservationSettings>lambdaQuery()
                        .eq(AirProductReservationSettings::getAirProductId, airProduct.getId())
        );
        //获取成本信息
        List<AirProductCostTouristDTO> list = airProductCostTouristService
                .getCurrentlyValidData(req.getProductId(), req.getDate());
        Assert.notEmpty(list, SystemError.AIR_PRODUCT_12025);
        //获取线上加幅
        AirProductChannelOnlineSelfPlatformDTO currentlyValidIncrease =
                airProductChannelOnlineSelfPlatformService.
                        getCurrentlyValidData(req.getProductId(), req.getDate(), req.getChannelId());
        Assert.nonNull(currentlyValidIncrease, SystemError.AIR_PRODUCT_12026);

        Map<Long, AirProductCostTouristDTO> touristMap = list.stream()
                .collect(Collectors.toMap(AirProductCostTouristDTO::getTouristTypeId, Function.identity()));
        //获取剩余库存
        Integer stock =  iAirProductSaleRecordService.getRemainingInventory(req.getProductId(), req.getDate());
        List<ProductFullPriceDTO> retList = Lists.newArrayList();
        req.getTouristTypes().stream().forEach(touristType -> {
            AirProductCostTouristDTO dto = touristMap.get(touristType);
            if (Objects.nonNull(dto)) {
                //售卖价格
                BigDecimal salePrice;
                /*****************计算加幅****************************/
                //加数值
                if (NumberConstant.ONE.getValue().equals(currentlyValidIncrease.getAdjustType())) {
                    salePrice = dto.getCostPrice().add(currentlyValidIncrease.getAmount());
                }
                //加百分比
                else {
                    salePrice = dto.getCostPrice().add(dto.getCostPrice().multiply(
                            BigDecimal.valueOf(currentlyValidIncrease.getPercent()).divide(BigDecimal.valueOf(100))
                    ));
                }
                /*****************计算服务费****************************/
                if (Objects.nonNull(reservationSettings)) {
                    //加百分比
                    if (NumberConstant.TWO.getValue().equals(reservationSettings.getServiceChargeType())) {
                        salePrice = salePrice.add(dto.getCostPrice().multiply(
                                reservationSettings.getServiceChargePrice()
                                        .divide(BigDecimal.valueOf(100))));
                    }
                    //加数值
                    else {
                        salePrice = salePrice.add(reservationSettings.getServiceChargePrice());
                    }
                }
                /******************加税费*******************************/
                BigDecimal taxes = dto.getAirProductCostTaxationDTOList().stream()
                        .map(AirProductCostTaxationDTO::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                salePrice = salePrice.add(taxes);
                retList.add(new ProductFullPriceDTO(touristType,  salePrice));
            }
        });
        return new ProductFullPriceAndStockDTO(airProduct.getId(), stock, retList);
    }

    /**
     * 联调使用，后面删除，
     * @return
     */
    @Override
    public HotCityDTO getHotCity() {
        String cn = "4RS";
        String xg = "CP4";
        String am = "824";
        String tw = "7ID";
        List<SysAreaDTO> countryWithin = sysAreaMapper.getCountryWithin(cn, xg, am, tw);
        List<SysAreaDTO> countryOutside = sysAreaMapper.getCountryOutside(cn, xg, am, tw);

        return new HotCityDTO(countryWithin , countryOutside);
    }

}
